package net.moonbiter.beanmapping;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import net.moonbiter.BugException;
import net.moonbiter.ReflectionException;

import org.apache.commons.beanutils.PropertyUtils;

/**
 * Take bean's properties values and put them in a Map.
 */
public class BeanMapper<BEAN> {
	private PropertyDescriptor[] propDescs;

	public BeanMapper(Class<BEAN> beanClass) {
		propDescs = PropertyUtils.getPropertyDescriptors(beanClass);
	}
	
	/**
	 * Make a bean's property appear in the map with a different name
	 * (but same value).
	 * @param propertyName
	 * @param keyMapName
	 */
	private void addTranslation(String propertyName, String keyMapName){
		// TODO implement
	}

	/**
	 * Take just the indicated properties.
	 * @param beanClass
	 * @param propertis
	 */
	public BeanMapper(Class<BEAN> beanClass, String[] propertiesNames) {
		// le prendo tutte
		PropertyDescriptor[] allPropDescs = PropertyUtils.getPropertyDescriptors(beanClass);		
		
		// scelgo solo quelle di interesse
		propDescs = new PropertyDescriptor[propertiesNames.length];
		int foundIndex = 0;
		for (PropertyDescriptor aProp : allPropDescs){
			if (isValueInCollection(aProp.getName(), propertiesNames)){
				propDescs[foundIndex++] = aProp;
			}
		}
		
		if (foundIndex<propertiesNames.length){
			throw new IllegalArgumentException("Unknown properties are listed");
		}
	}
	
	private static boolean isValueInCollection(String value, String[] collection){
		for (String s : collection){
			if (s.equals(value)){
				return true;
			}
		}
		return false;
	}
	
	public Map<String, Object> doMapping(BEAN beanInstance) throws ReflectionException {
		return doMapping(beanInstance,"");
	}
	
	public Map<String, Object> doMapping(BEAN beanInstance, String prefix) throws ReflectionException {
		Map<String, Object> map = new HashMap<String, Object>();		
		return doMapping(beanInstance,prefix,map);
	}
	
	public Map<String, Object> doMapping(BEAN beanInstance, String prefix, Map<String,Object> map) throws ReflectionException {
		for (PropertyDescriptor prop : propDescs){
			try {
				map.put(prefix+prop.getName(),PropertyUtils.getProperty(beanInstance, prop.getName()));
			} catch (IllegalAccessException e) {
				throw new ReflectionException(e);
			} catch (InvocationTargetException e) {
				throw new ReflectionException(e);
			} catch (NoSuchMethodException e) {
				throw new BugException("I selected just existing properties...");
			}
		}
		return map;
	}
}
